// PARADIME INTERPRETER
//
//LICENSED FREELY UNDER MIT.
//CREATED FOR FREE USE.
#include "stdafx.h"
#include "tokentypes.h"
#include "Interpreter.h"
#include "variabledomain.h"
#include "variant.h"
#include "Parser.h"
#include "errorcodes.h"


int ExecuteCode(std::vector<token>* code, Interpreter* CodeOwner, int* codepos, VariableDomain* domain, char context)
{
	int NestedLevel = 0; //Used for keeping track of nested control blocks.
	int dims[VAR_SUBSCRIPT_MAX];

	int iterator = *codepos;
	for (;iterator<code->size();iterator++){
			switch(context)
			{
			case PCONTEXT_STANDARD_EXEC: case PCONTEXT_IFBLOCK_EXEC: case PCONTEXT_IFLINE_EXEC: case PCONTEXT_WHILEBLOCK_EXEC:
				switch((*code)[iterator].type)
				{

				case GLOBAL_KEYWORD_TOK:
					iterator++;
					if((*code)[iterator].type == CONSTANT_KEYWORD_TOK)iterator++;

					Parse_GlobalDeclaration( code, &iterator, CodeOwner, domain);
					break;




				case FUNC_UNKNOWN_TOK:
					{
						std::vector<token> expression;
						while((*code)[iterator].type!=EOL_TOK)
						{
							expression.push_back((*code)[iterator]);
							iterator++;
						}
						token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
						Free_Token_Attributes( &result);
						Destroy_Vector_Elements( &expression);
					}
					//Discard the result.
					break;

				case ARRAY_VARIABLE_TOK:
					{
						std::string varname = (*code)[iterator].data;
						Variant* var = domain->Lookup(varname);
						iterator++;
						if(var==0)
							return PARSER_ERR_SUBSCRIPTUSED_NONARRAYVAR;

						for(int u=0;u<VAR_SUBSCRIPT_MAX;u++)
							dims[u] = 0;

						if(Parse_ArraySubscripts( (int*)&dims, code, &iterator, CodeOwner, domain)!=PARSER_SUCCESS)
							return PARSER_ERR_INVALIDSUBSCRIPT;

						var = var->ArrayGetRef( (int*)&dims, true);

						iterator++;
						std::vector<token> expression;
						while((*code)[iterator].type!=EOL_TOK)
						{
							expression.push_back((*code)[iterator]);
							iterator++;
						}

						token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
						token* res = &result;
						var->SetFromToken((void*)res);
						Free_Token_Attributes( res);
						Destroy_Vector_Elements( &expression);
				}
					break;


				case VARIANT_VARIABLE_TOK:
					if((*code)[iterator+1].type==EQUAL_TOK){
						std::string varname = (*code)[iterator].data;
						Variant* var = domain->Lookup(varname);
						if(var==0){
							var = new Variant(0);
							domain->Assign( varname, var);
						}
						iterator+=2;
						std::vector<token> expression;
						while((*code)[iterator].type!=EOL_TOK)
						{
							expression.push_back((*code)[iterator]);
							iterator++;
						}

						token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
						token* res = &result;
						var->SetFromToken((void*)res);
						Free_Token_Attributes( res);
						Destroy_Vector_Elements( &expression);

					}else{ 
						//INVALID LINE, THROUGH ERROR
					}
					break;


				case WHILE_TOK:
					if((*code)[iterator].data == "WHILE"){ //WHILE statement
						iterator++;
						std::vector<token> expression;
						while((*code)[iterator].type!=EOL_TOK)
						{
							expression.push_back((*code)[iterator]);
							iterator++;
						}
						iterator++;

						int whilepos = iterator;
						//Is the condition true?
						token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
						token* res = &result;
						if(IsTrue(res)){
							while(IsTrue(res))
							{
								Free_Token_Attributes( res);
								iterator = whilepos;
								ExecuteCode( code, CodeOwner, &iterator, domain, PCONTEXT_WHILEBLOCK_EXEC);
								result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);	
							}
						}
						else if(!IsTrue(res)){
							Free_Token_Attributes( res);
							ExecuteCode( code, CodeOwner, &iterator, domain, PCONTEXT_WHILEBLOCK_PASS);
						}
						Destroy_Vector_Elements( &expression);
					}else if(((*code)[iterator].data == "WEND")){
							if(context == PCONTEXT_WHILEBLOCK_EXEC){
								iterator++;
								*codepos = iterator;
								return PARSER_SUCCESS;
							}
					}
					break;




				case IF_TOK:

					if((*code)[iterator].data == "IF"){ //IF statement
						iterator++;
						std::vector<token> expression;
						while((*code)[iterator].type!=IF_TOK)
						{
							expression.push_back((*code)[iterator]);
							iterator++;
						}
						iterator++;

						//Is the condition true?
						token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
						token* res = &result;
						if(!IsTrue(res)){
							Free_Token_Attributes( res);
							//Condition NOT true, jump to end of statement
							if((*code)[iterator].type==EOL_TOK)
							{	//Multiline IF statement
								//Code to skip over the contents of the block.
								ExecuteCode( code, CodeOwner, &iterator, domain, PCONTEXT_IFBLOCK_PASS);
							}else{//Single lined IF statement
								while((*code)[iterator].type!=EOL_TOK)
								{
									iterator++;
								}
							}
						}else{	//Condition is true...PERFORM IF STATEMENT
							Free_Token_Attributes( res);
							if((*code)[iterator].type==EOL_TOK)
							{	//Multiline IF statement
								//Code to execute the block.
								ExecuteCode( code, CodeOwner, &iterator, domain, PCONTEXT_IFBLOCK_EXEC);
							
							}else{//Single lined IF statement
								std::vector<token> block;
								while((*code)[iterator].type!=EOL_TOK)
								{
									block.push_back( (*code)[iterator]);
									iterator++;
								}
								//Add the EOL token
								block.push_back( (*code)[iterator]);

								int iPos = 0;
								ExecuteCode( &block, CodeOwner, &iPos, domain, PCONTEXT_IFLINE_EXEC);
							}
						}
						Free_Token_Attributes( res);
						Destroy_Vector_Elements( &expression);

					} // if(..=="IF")
					else if(((*code)[iterator].data == "ENDIF")){
							if(context == PCONTEXT_IFBLOCK_EXEC){
								iterator++;
								*codepos = iterator;
								return PARSER_SUCCESS;
							}
					}else if(((*code)[iterator].data == "ELSE")  ||
							((*code)[iterator].data == "ELSEIF"))
					{
						if(context == PCONTEXT_IFBLOCK_EXEC)
							context = PCONTEXT_IFBLOCK_IGNORE;
					}
					break;
				}
				break;


			case PCONTEXT_WHILEBLOCK_PASS:
				if((*code)[iterator].type == WHILE_TOK)
				{
					if((*code)[iterator].data == "WHILE")
						NestedLevel++;
					else if((*code)[iterator].data == "WEND")
					{
						if(!NestedLevel){//Time to unwind recursion.
							iterator++;
							*codepos = iterator;
							return PARSER_SUCCESS;
						}else
							NestedLevel--;
					}
				}
				break;


			case PCONTEXT_IFBLOCK_PASS: case PCONTEXT_IFBLOCK_IGNORE:
				if((*code)[iterator].type == IF_TOK)
				{
					//We have reached an IF statement. If it
					//is NOT single lined, we need to keep track of it
					//cause its nested.
					if((*code)[iterator].data == "IF"){
						while((*code)[iterator].type!=EOL_TOK)iterator++;
						if((*code)[iterator-1].type == IF_TOK)
							NestedLevel++;	//There is a THEN, therefore muiltilined/nested.
					}else if((*code)[iterator].data == "ENDIF"){
						if(!NestedLevel){//Time to unwind recursion.
							iterator++;
							*codepos = iterator;
							return PARSER_SUCCESS;
						}else
							NestedLevel--;
					}
					else if((*code)[iterator].data == "ELSE"){
						if(context == PCONTEXT_IFBLOCK_PASS)
							context = PCONTEXT_IFBLOCK_EXEC;

					}
					else if((*code)[iterator].data == "ELSEIF"){
						if(context == PCONTEXT_IFBLOCK_PASS){
							iterator++;
							std::vector<token> expression;
							while((*code)[iterator].type!=IF_TOK)
							{
								expression.push_back((*code)[iterator]);
								iterator++;
							}
							iterator++;
							token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
							token* res = &result;
							if(IsTrue(res))
								context = PCONTEXT_IFBLOCK_EXEC;
							Free_Token_Attributes( res);
							
						}
					}
				}
				break;
			}
	}
	*codepos = iterator;
	return PARSER_SUCCESS;
}


void Free_Token_Attributes(token* tok){

	if(tok->type == OPT_STRINGLITERAL_TOK)
	{
		//MessageBoxA(NULL, tok->szValue, "Debug::Memory De-Allocation", 0x10);
		delete [] tok->szValue;
	}

	tok->type = OPT_INT32_TOK;//Prevent accidental freeing of nothing.
}

void Destroy_Vector_Elements(std::vector<token>* in){

	//Made redundant.
	return;

	while(in->size()){
		Free_Token_Attributes(&(*in)[0]);
		in->pop_back();
	}
		

}

int Parse_GlobalDeclaration(std::vector<token>* code, int* iterator, Interpreter* CodeOwner, VariableDomain* domain){

	int count = *iterator;
	int nestedlevel = 0;
	int dims[VAR_SUBSCRIPT_MAX];
	int IsArrayDec = 0;


	while((*code)[count].type != EOL_TOK)
	{
		std::string varname;
		std::vector<token> expression;
		VariableDomain* dom = (VariableDomain*)CodeOwner->Domain;
		int good = 1;
		int WasDeclaration = 1;

		switch((*code)[count].type){
			case ARRAY_VARIABLE_TOK:
				varname = (*code)[count].data;
				count++;
				for(int u=0;u<VAR_SUBSCRIPT_MAX;u++)
					dims[u] = 0;

				if(Parse_ArraySubscripts( (int*)&dims, code, &count, CodeOwner, domain)!=PARSER_SUCCESS)
				{
					//ERROR!
				};
				WasDeclaration = 0;
				IsArrayDec = 1;
				break;

			case VARIANT_VARIABLE_TOK:
				varname = (*code)[count].data;
				count++;
				if((*code)[count].type == PARAM_SEPARATOR_TOK)
				{	//No declaration, only initialisation.
					good = 0;
					WasDeclaration = 0;
					break;
				}
				count++; //Get past '$var' and '=' tokens.
				good = 1;

				//Collect the expression
				while(good)
				{
					WasDeclaration = 1;
					if((*code)[count].type == EOL_TOK)
						break;

						switch((*code)[count].type)
						{
							case LFT_BRACKET_TOK:
								nestedlevel++;
								expression.push_back((*code)[count]);
								break;
							case RHT_BRACKET_TOK:
								nestedlevel--;
								expression.push_back((*code)[count]);
								break;

							case PARAM_SEPARATOR_TOK:
								if(nestedlevel==0)
								{
									good = 0;
									break;
								}
							default:
								expression.push_back((*code)[count]);
								break;
						}
					if(good)count++;
				}
				break;

			case PARAM_SEPARATOR_TOK:
				count++;
				continue;
				break;

			default:
				{
				char f[10];
				itoa((*code)[count].type, f, 10);
				MessageBox(NULL, "Parser Error: Unexpected token", f, 0x10);
				}

		}
		Variant* var = dom->Lookup(varname);
		if(var==0){
			var = new Variant(0);
			domain->Assign( varname, var);
		}

		if(IsArrayDec)
			var->DeclareAsArray((int*)&dims);


		if(WasDeclaration){
			token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
			token* res = &result;
			var->SetFromToken((void*)res);
			Free_Token_Attributes( res);
			Destroy_Vector_Elements( &expression);
		}

		if((*code)[count].type == EOL_TOK){
			*iterator = count;
			return PARSER_SUCCESS;
		}
		
		count++;//must of been a comma.
	}


	*iterator = count;
	return PARSER_SUCCESS;
}




int Parse_ArraySubscripts(int* subs, std::vector<token>* code, int* iterator, Interpreter* CodeOwner, VariableDomain* domain)
{

	int count = *iterator;
	int nestedlevel = 0; //Nested ARRAYS, not functions in this case.
	int currentdimension = 1;

	//When we start, should be at left array paranthesis.
	if((*code)[count].type != LFT_ARRAY_PARANTH_TOK)
		return PARSER_ERROR_ARRAYSYNTAX;



	while((count < code->size()) && 
		((*code)[count].type == LFT_ARRAY_PARANTH_TOK)){
		count++;
		std::vector<token> expression;
		int continueloop = 1;
		while(continueloop)
		{
			switch((*code)[count].type)
			{
			case LFT_ARRAY_PARANTH_TOK:
				nestedlevel++;
				expression.push_back((*code)[count]);
				break;
			case RHT_ARRAY_PARANTH_TOK:
				if(nestedlevel == 0){
					continueloop = 0;
					break;
				}
				nestedlevel--;
				expression.push_back((*code)[count]);
				break;
			default:
				expression.push_back((*code)[count]);
				break;
			}
			count++;
		}
		//We just collected the tokens that make up that subscript.
		token result = EvaluateRPN(ShuntExpression(&expression,CodeOwner),CodeOwner);
		//Verify that the result is a valid integer
		if(result.type == PARSER_VARIABLE)
		{
			result.nValue = result.ResolvedVariable->GetInt32();
			result.type = OPT_INT32_TOK;
		}
		if(result.type != OPT_INT32_TOK)
			return PARSER_ERR_INVALIDSUBSCRIPT;


		subs[currentdimension] = result.nValue;
		currentdimension++;
	}
	*iterator = count;
	subs[0] = currentdimension-1;

	return PARSER_SUCCESS;
}